package com.easylinkin.linkappapi.facerecognition.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.facerecognition.entity.FacePhoto;
import com.easylinkin.linkappapi.facerecognition.entity.RecognitionRecord;
import com.easylinkin.linkappapi.facerecognition.service.FacePhotoService;
import com.easylinkin.linkappapi.facerecognition.service.RecognitionRecordService;
import com.easylinkin.linkappapi.facerecognition.service.oss.ObjectStorageOutsideService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

@RestController
@RequestMapping("/recognition")
public class RecognitionRecordController {

    private static final Logger log = LoggerFactory.getLogger(RecognitionRecordController.class);

    @Autowired
    private RecognitionRecordService recognitionRecordService;

    private static Pattern fileNamePattern = null;

    @Value("${oss.bucket}")
    private String bucket;

    @Value("${oss.dir}")
    private String dir;

    @Autowired
    @Qualifier("oss")
    private ObjectStorageOutsideService ossClient;

    @Resource
    LinkappUserContextProducer linkappUserContextProducer;

    @Autowired
    private FacePhotoService facePhotoService;

    @PostMapping("/record")
    public RestMessage queryRecords(@RequestBody RequestModel<RecognitionRecord> requestModel) {

        IPage<RecognitionRecord> record = recognitionRecordService.queryRecognitionRecordList(requestModel.getPage(), requestModel.getCustomQueryParams());
        record.getRecords().forEach(this::checkPersonnelPhotoInfo);
        return RestBuilders.successBuilder().data(record).build();
    }

    @PostMapping("/batch/delete")
    public RestMessage batchDeleteCamera(@RequestParam("ids") String ids) {
        if (ids == null || ids.isEmpty()) {
            return RestBuilders.successBuilder().build();
        }

        List<String> recordIds = Arrays.asList(ids.split(","));
        String currentTenantId = linkappUserContextProducer.getCurrent().getTenantId();
        List<Long> deniedIds = recognitionRecordService.listByIds(recordIds).stream()
                .filter(r -> !r.getTenantId().equalsIgnoreCase(currentTenantId))
                .mapToLong(RecognitionRecord::getId)
                .boxed()
                .collect(Collectors.toList());

        if (deniedIds.size() != 0) {
            return RestBuilders.failureBuilder().message("无权删除").data(deniedIds).build();
        }


        if (!recognitionRecordService.removeByIds(recordIds)) {
            return RestBuilders.failureBuilder().message("批量删除识别记录失败").build();
        }

        return RestBuilders.successBuilder().build();
    }

    private void checkPersonnelPhotoInfo(RecognitionRecord record) {
        String photoUrl = record.getCapturePhoto();
        if (photoUrl != null) {
            if (isExpired(photoUrl)) {

                try {
                    String s = reGenerateOssUrl(URLDecoder.decode(photoUrl, "utf-8"));
                    record.setCapturePhoto(s);

                    recognitionRecordService.updateById(record);
                } catch (UnsupportedEncodingException e) {
                    log.error("decode capture photo url {} error {}", photoUrl, e.getMessage());
                }
            }
        }

        String recognitionPhotoUrl = record.getRecognitionPhoto();
        if (recognitionPhotoUrl != null) {
            if (isExpired(recognitionPhotoUrl)) {

                try {
                    String s = reGenerateOssUrl(URLDecoder.decode(recognitionPhotoUrl, "utf-8"));
                    record.setRecognitionPhoto(s);

                    recognitionRecordService.updateById(record);

                    FacePhoto facePhoto = facePhotoService.queryPhotoWithUrl(recognitionPhotoUrl);
                    if (!Objects.isNull(facePhoto)){
                        facePhoto.setPhotoUrl(s);
                        facePhotoService.updateById(facePhoto);
                    }

                } catch (UnsupportedEncodingException e) {
                    log.error("decode recognition photo url {} error {}", photoUrl, e.getMessage());
                }
            }
        }
    }

    private String reGenerateOssUrl(String originalUrl) {
        if (fileNamePattern == null) {
            String pattern = "/(" + dir + ".*)\\?"; //取出bucket 到 ? 之间的内容
            fileNamePattern = Pattern.compile(pattern);
        }

        Matcher matcher = fileNamePattern.matcher(originalUrl);
        if (matcher.find()) {
            String originalFilename = matcher.group(1);
            return ossClient.generatePresignedUrl(bucket, originalFilename, 7 * 24 * 60 * 60);
        }

        return originalUrl;
    }

    private boolean isExpired(String ossUrl) {
        String[] ossUrls = ossUrl.split("\\?");
        if (ossUrls.length == 1){
            return false;
        }
        String[] segments = ossUrls[1].split("&");
        Instant xDate = null;
        long expireSeconds = 0;
        for (String segment : segments) {

            // minio 的过期时间点
            if (segment.startsWith("X-Amz-Date")) {
                DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
                try {
                    xDate = Instant.ofEpochMilli(dateFormat.parse(segment.split("=")[1]).getTime());
                } catch (ParseException e) {
                    log.error("Parse koala expire date {} error {}", segment.split("=")[1], e.getMessage());
                    return true;
                }
            }
            if (segment.startsWith("X-Amz-Expires")) {
                expireSeconds = Long.parseLong(segment.split("=")[1]);
            }

            // 阿里链接的过期时间点
            if (segment.startsWith("Expires")) {
                xDate = Instant.ofEpochSecond(Long.parseLong(segment.split("=")[1]));
            }
        }

        if (xDate == null) {
            return true;
        }

        return Instant.now().isAfter(xDate.plusSeconds(expireSeconds));
    }
}
